package model

import (
	"battle-server/manager"
	"fmt"
	gameModel "game-server/model"
	"math/rand"
	"time"
)

// SkillTarget 技能目标类型
type SkillTarget int

const (
	TargetEnemyFront  SkillTarget = 1 // 敌方前排
	TargetEnemyBack   SkillTarget = 2 // 敌方后排
	TargetEnemyAll    SkillTarget = 3 // 敌方全体
	TargetEnemySingle SkillTarget = 4 // 敌方单体
	TargetAllySingle  SkillTarget = 5 // 友方单体
	TargetAllyAll     SkillTarget = 6 // 友方全体
	TargetSelf        SkillTarget = 7 // 自身
)

// SkillExecutor 技能执行器接口
type SkillExecutor interface {
	Execute(caster *FightHero, targets []*FightHero) []string
	GetID() int
	GetName() string
	GetCD() int
	GetDescription() string
}

// BaseSkill 基础技能结构
type BaseSkill struct {
	ID          int
	Name        string
	CD          int
	Description string
}

func (bs BaseSkill) GetID() int             { return bs.ID }
func (bs BaseSkill) GetName() string        { return bs.Name }
func (bs BaseSkill) GetCD() int             { return bs.CD }
func (bs BaseSkill) GetDescription() string { return bs.Description }

/*
*
伤害计算
*/
func (bs BaseSkill) applyDamage(caster *FightHero, target *FightHero, effect *gameModel.SkillEffect) int {
	// 不同类型使用不同的伤害基数：物理or魔法
	damageBase := 0
	casterJob := caster.Job
	if casterJob == 1 || casterJob == 3 || casterJob == 4 || casterJob == 6 {
		damageBase = caster.Attack
	} else {
		damageBase = caster.MagicPower
	}

	// 计算伤害
	damage := effect.Value * damageBase
	// 防御
	defense := target.Defense
	// 基础免伤
	reduction := target.DamageReduction
	// 玩家身上防御buff
	for _, buff := range target.Buffs {
		if buff.Type == EffectAddDefense {
			addDefense := defense * (buff.Value / 10000.0)
			defense += addDefense
		}
	}

	// 按照优先级来减伤害
	// 1. 护甲减少10%
	damage -= int(float64(damage) * 0.1)
	// 2. 基础免伤10%
	damage -= int(float64(damage) * reduction)

	// 应用伤害
	// 1.如果有护盾，那么扣去护盾先
	if target.Shield > damage {
		target.Shield -= damage
	} else {
		damage -= target.Shield
		target.Shield = 0
		// 扣除英雄血量
		target.CurrentHp -= damage
		target.CurrentHp = max(target.CurrentHp, 0)
	}

	return damage
}

/*
*
技能效果添加
*/
func (bs BaseSkill) addSkillEffect(target *FightHero, caster *FightHero, effects []*gameModel.SkillEffect, logs []string) {
	for _, effect := range effects {
		if effect.Duration == 0 {
			continue
		}
		randomInt := rand.Intn(10000)
		if effect.ValueType == 1 || randomInt <= effect.Chance {
			stunEffect := Effect{
				Type:        SkillEffectType(effect.EffectType),
				Value:       effect.Value,
				Duration:    effect.Duration,
				SourceId:    caster.HeroId,
				AppliedTime: time.Now(),
			}
			// buff
			if IsBuffEffect(SkillEffectType(effect.EffectType)) {
				target.Buffs = append(target.Buffs, stunEffect)
			} else {
				target.Buffs = append(target.Debuffs, stunEffect)
			}
			logs = append(logs, fmt.Sprintf("英雄被添加了 %d 效果 %s", effect.EffectType, effect.Description))
		}

	}
}

// 检查目标是否死亡
func checkTargetIsAlive(target *FightHero) bool {
	if target.CurrentHp <= 0 {
		target.CurrentHp = 0
		target.IsAlive = false
	}
	return target.IsAlive
}

/*********************************** 技能工厂，用于创建技能实例 ******************************/

type SkillFactory struct{}

func NewSkillFactory() SkillFactory {
	return SkillFactory{}
}

func (sf *SkillFactory) CreateSkill(skillID int) SkillExecutor {
	switch skillID {
	case 1:
		return NewFortitudeSkill(skillID)
	case 2:
		return NewGroundSlamSkill(skillID)
	// 其他技能...
	default:
		return nil
	}
}

/****************** 以下是各个英雄技能的具体实现  ****************************/

// 坚韧守卫技能1：坚不可摧
type FortitudeSkill struct {
	BaseSkill
}

func NewFortitudeSkill(skillId int) *FortitudeSkill {
	skill, _ := manager.GteSkillById(skillId)
	return &FortitudeSkill{
		BaseSkill: BaseSkill{
			ID:          skill.SkillID,
			Name:        skill.SkillName,
			CD:          skill.Cooldown,
			Description: skill.Description,
		},
	}
}

func (s *FortitudeSkill) Execute(caster *FightHero, targets []*FightHero) []string {
	logs := make([]string, 0)
	logs = append(logs, "英雄"+string(caster.HeroId)+"使用了技能："+s.Name)

	// 添加防御增益效果
	target := targets[0]
	effects, err := manager.GetSkillEffects(s.GetID())
	if err != nil {
		logs = append(logs, fmt.Sprintf("技能 %d 无法获取技能效果", s.GetID()))
		return logs
	}
	s.addSkillEffect(target, caster, effects, logs)

	return logs
}

// 坚韧守卫技能2：震地一击
type GroundSlamSkill struct {
	BaseSkill
}

func NewGroundSlamSkill(skillId int) *GroundSlamSkill {
	skill, _ := manager.GteSkillById(skillId)
	return &GroundSlamSkill{
		BaseSkill: BaseSkill{
			ID:          skill.SkillID,
			Name:        skill.SkillName,
			CD:          skill.Cooldown,
			Description: skill.Description,
		},
	}
}

func (s *GroundSlamSkill) Execute(caster *FightHero, targets []*FightHero) []string {
	logs := make([]string, 0)
	logs = append(logs, "英雄"+string(caster.HeroId)+"使用了技能："+s.Name)

	// 计算伤害
	effect, err := manager.GetDirectEffect(s.GetID())
	if err != nil {
		logs = append(logs, fmt.Sprintf("技能%d 不存在直接技能效果", s.GetID()))
		return logs
	}

	// 对每个目标造成伤害
	effects, err := manager.GetSkillEffects(s.GetID())
	if err != nil {
		logs = append(logs, fmt.Sprintf("技能%d 不存在技能效果", s.GetID()))
		return logs
	}

	for _, target := range targets {
		// 应用伤害
		damage := s.applyDamage(caster, target, effect)
		logs = append(logs, fmt.Sprintf("英雄%d 使用了 %d 造成了 %d 点伤害", caster.HeroId, s.GetID(), damage))

		// 技能效果添加
		s.addSkillEffect(target, caster, effects, logs)

		alive := checkTargetIsAlive(target)
		if !alive {
			logs = append(logs, "英雄"+string(target.HeroId)+"阵亡！")
		}

	}
	return logs
}
